#include "bitstream"
#include "Aritmetico"

Aritmetico::Aritmetico() {
	this->inicializar();
}

void Aritmetico::inicializar() {
	// Inicializo las variables
	_piso = 0;
	_medio = USHORT_MAXBIT;
	_techo = USHORT_MAX;
}

void Aritmetico::finalizar() {
	//emito los bits del buffer como si converge al piso
	//ya que voy a emitir el piso como valor final del aritmético
	//this->procesarUnderflow(0); 27/05/2012 esto pasa a ser parte del procesarResultArit
	//el piso contiene el valor final resultado de la compresion
	this->procesarResultArit();
	this->inicializar();
}

bool Aritmetico::convergioAlTecho() {
	return((_piso & _techo) >= _medio);
}

bool Aritmetico::convergioAlPiso() {
	return ((_techo | _piso) <= _medio);
}

bool Aritmetico::hayUnderflow() {
	//ver optimizacion, solo hay underflow los 3 siguientes bits mas significativos tienen underflow
	//hacerlo con ifs anidados, esto me permite poder escribir el numero del aritmetico con 15 bits
	//si no tendria que revisar la renormalizacion para obtener algun bit de ahorro extra y es medio complicado
	//aun así, se pueden hacer las dos cosas
	//"La optimización prematura es la raíz de todos los males. Donald Knuth"
	return((((_piso<<1)&USHORT_MAX) >= _medio) and (((_techo<<1)&USHORT_MAX) < _medio));
}

void Aritmetico::piso(ushort valor) {
	_piso = valor;
}

void Aritmetico::techo(ushort valor) {
	_techo = valor;
}

ushort Aritmetico::piso() {
	return (_piso);
}

ushort Aritmetico::techo() {
	return (_techo);
}

void Aritmetico::renormalizarMaxBit() {
	_techo = ((_techo<<1)|1);
	_piso = (_piso<<1);
}


void Aritmetico::corregirUnderflow() {
	_techo = (((_techo<<1)&USHORT_MAX)|_medio)|1;
	_piso = (_piso<<1)&(~_medio);
}



void Aritmetico::proximo(ushort low, ushort fv, ushort ft) {

	//low = frecuencia acumulada en el nivel previa al caracter
	//fv = frecuencia del valor a comprimir
	//ft = sumatoria total de frecuencias en el nivel
	// Unifico el criterio con el Descompresor::intervalo, para evitar "peleas"
	int nuevoPiso = damePiso(low,ft);
	int nuevoTecho = damePiso(low+fv,ft)-1;

	piso(nuevoPiso);
	techo(nuevoTecho);


	renormalizar();
}

int Aritmetico::damePiso(int low, int ft)
{
	//low = frecuencia acumulada en el nivel previa al caracter
	//ft = sumatoria total de frecuencias en el nivel

	// Recibo la frecuencia acumulada anterio y devuelvo el piso
	int rangoTotal = _techo - _piso + 1;
	double rangoFrecuencia = (double)rangoTotal / ft;
	double auxPiso = rangoFrecuencia * low;
	int returnPiso = _piso + auxPiso;
	if ((double)returnPiso<(_piso + auxPiso)) returnPiso += 1;

	// Cochinada fea para ver que pasa
	if(low==ft) returnPiso = _techo + 1;
	return returnPiso;
}

ushort Aritmetico::intervalo(ushort)
{
	return 0;
}

